package com.coocaa.x.service.liteservice;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.RemoteException;

import com.coocaa.x.framework.app.CoocaaApplication;
import com.coocaa.x.framework.utils.Android;
import com.coocaa.x.framework.utils.Cache;
import com.coocaa.x.framework.utils.LogUtils;
import com.coocaa.x.service.ErrorCode;
import com.coocaa.x.service.LiteBaseService;
import com.coocaa.x.service.XServiceManager.XServiceConnection;
import com.coocaa.x.service.litecache.LiteCacheStub;
import com.coocaa.x.service.litecache.aidl.ILiteCacheService;
import com.coocaa.x.service.liteccconnecter.CoocaaDEConnecter;
import com.coocaa.x.service.liteccconnecter.CoocaaIPCConnecter;
import com.coocaa.x.service.liteccconnecter.LiteCCConnectorServiceStub;
import com.coocaa.x.service.liteccconnector.aidl.ILiteCCConnectorService;
import com.coocaa.x.service.liteconfig.LiteConfigServiceStub;
import com.coocaa.x.service.liteconfig.aidl.ILiteConfigService;
import com.coocaa.x.service.litedaemon.LiteDaemonServiceStub;
import com.coocaa.x.service.litedb.LiteDBServiceStub;
import com.coocaa.x.service.litedb.aidl.ILiteDBService;
import com.coocaa.x.service.litedownloader.DownloaderStub;
import com.coocaa.x.service.litedownloader.aidl.IDownloaderService;
import com.coocaa.x.service.liteplayer.LitePlayerClientServiceStub;
import com.coocaa.x.service.liteplayer.LitePlayerKernelServiceStub;
import com.coocaa.x.service.liteplayer.aidl.ILitePlayerClientService;
import com.coocaa.x.service.liteplayer.aidl.ILitePlayerKernelProxyService;
import com.coocaa.x.service.litepm.PMServiceStub;
import com.coocaa.x.service.litepm.aidl.ILitePMService;
import com.coocaa.x.service.litepush.LitePushServiceStub;
import com.coocaa.x.service.liteservice.aidl.ILiteService;
import com.coocaa.x.service.liteservice.aidl.ILiteServiceListener;
import com.coocaa.x.service.liteuser.LiteUserStub;
import com.coocaa.x.service.liteuser.aidl.ILiteUserService;

import java.util.List;
import java.util.Vector;

public class LiteService extends LiteBaseService {
    private static class MyStub extends ILiteService.Stub {
        private static final XServiceConnection<?>[] CONNECTERS = {};
//        {LitePMConnecter.connecter,
//                LiteDBConnecter.connecter, LiteCacheConnecter.connecter,
//                LiteCCConnectorConnecter.connecter, LiteUserConnecter.connecter,
//                LiteDaemonConnecter.connecter, LitePlayerKernelServiceConnecter.connecter,
//                LitePlayerClientServiceConnecter.connecter, LiteConfigConnecter.connecter,
//                LiteDownloadConnecter.connecter, LitePushConnector.connecter};

        private Cache<String, XServiceConnection<?>> connectersMap = new Cache<String, XServiceConnection<?>>();
        private Cache<String, XServiceConnection<?>> regConnectersMap = new Cache<String, XServiceConnection<?>>();

        private Vector<AIDLInterface<ILiteServiceListener>> listeners = new Vector<AIDLInterface<ILiteServiceListener>>();
        private Context mContext = null;

        private Boolean bStarted = false;

        private PMServiceStub pmServiceStub = null;
        private LiteDBServiceStub dbServiceStub = null;
        private LiteCacheStub cacheServiceStub = null;
        private LiteCCConnectorServiceStub cccServiceStub = null;
        private LiteUserStub userServiceStub = null;
        private LiteDaemonServiceStub daemonServiceStub = null;
        private LitePlayerKernelServiceStub playerKernelServiceStub = null;
        private LitePlayerClientServiceStub playerClientServiceStub = null;
        private LiteConfigServiceStub configServiceStub = null;
        private DownloaderStub downloaderServiceStub = null;
        private LitePushServiceStub pushServiceStub = null;


        public MyStub(Context context) {
            mContext = context;
            for (XServiceConnection<?> c : CONNECTERS) {
                synchronized (connectersMap) {
                    connectersMap.add(c.getAction(), c);
                }
            }
        }


        @Override
        public void whoAmI() {
            LogUtils.d("wai", "<<LiteService>> who am i??  " + mContext.getPackageName());
            try {
                getPMService().whoAmI();
                getDBService().whoAmI();
                getCacheService().whoAmI();
                getCCConnectorService().whoAmI();
                getUserService().whoAmI();
                getPlayerKernelProxyService().whoAmI();
                getPlayerClientService().whoAmI();
                getConfigService().whoAmI();
                getDownloaderService().whoAmI();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void addListener(ILiteServiceListener l) {
            synchronized (listeners) {
                if (l != null) {
                    IBinder binder = l.asBinder();
                    AIDLInterface<ILiteServiceListener> i = new AIDLInterface<ILiteServiceListener>(
                            binder, l);
                    listeners.add(i);
                }
            }
        }

        @Override
        public void removeListener(ILiteServiceListener l) {
            synchronized (listeners) {
                if (l != null) {
                    IBinder binder = l.asBinder();
                    for (AIDLInterface<ILiteServiceListener> i : listeners) {
                        if (i.binder == binder) {
                            listeners.remove(i);
                            break;
                        }
                    }
                }
            }
        }

        @Override
        public void start() throws RemoteException {
            synchronized (bStarted) {
                if (bStarted)
                    return;
                bStarted = true;
                CoocaaApplication.post(new Runnable() {
                    @Override
                    public void run() {
                        int state = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
                        if (Android.setComponentEnabledSetting(mContext, CoocaaDEConnecter.getComponentName(mContext), state))
                            check(mContext, CoocaaDEConnecter.getComponentName(mContext), state);

                        if (Android.setComponentEnabledSetting(mContext, CoocaaIPCConnecter.getComponentName(mContext), state))
                            check(mContext, CoocaaIPCConnecter.getComponentName(mContext), state);
                        List<XServiceConnection<?>> connectors = connectersMap.values();
                        for (XServiceConnection<?> c : connectors)
                            c.bindService(mContext, mContext.getPackageName());


                        pmServiceStub = new PMServiceStub(mContext);
                        dbServiceStub = new LiteDBServiceStub(mContext);
                        cacheServiceStub = new LiteCacheStub(mContext);
                        cccServiceStub = new LiteCCConnectorServiceStub(mContext);
                        userServiceStub = new LiteUserStub(mContext);
                        daemonServiceStub = new LiteDaemonServiceStub(mContext);
                        playerKernelServiceStub = new LitePlayerKernelServiceStub(mContext);
                        playerClientServiceStub = new LitePlayerClientServiceStub(mContext);
                        configServiceStub = new LiteConfigServiceStub(mContext);
                        downloaderServiceStub = new DownloaderStub(mContext);
                        pushServiceStub = new LitePushServiceStub(mContext);
                    }
                });
            }
        }

        @Override
        public void stop() throws RemoteException {
            synchronized (bStarted) {
                if (!bStarted)
                    return;
                bStarted = false;
                List<XServiceConnection<?>> connectors = connectersMap.values();
                for (XServiceConnection<?> c : connectors)
                    c.unbindService(mContext);

                synchronized (listeners) {
                    for (final AIDLInterface<ILiteServiceListener> i : listeners) {
                        try {
                            i.i.willOnStop();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }

//        @Override
//        public void disable() throws RemoteException {
//            synchronized (listeners) {
//                for (final AIDLInterface<ILiteServiceListener> i : listeners) {
//                    try {
//                        i.i.willOnDisable();
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                    }
//                }
//            }
//
////            LiteServiceConnecter.setEnable(mContext, false);
////
////            int state = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
////            Android.setComponentEnabledSetting(mContext, CoocaaDEConnecter.getComponentName(mContext), state);
////            check(mContext, CoocaaDEConnecter.getComponentName(mContext), state);
////
////            Android.setComponentEnabledSetting(mContext, CoocaaIPCConnecter.getComponentName(mContext), state);
////            check(mContext, CoocaaIPCConnecter.getComponentName(mContext), state);
//        }

        private static void check(Context context, ComponentName cn, int state) {
            while (state != Android.getComponentEnabledSetting(context, cn))
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }

        @Override
        public synchronized int registerService(String pkgName, String arg0) throws RemoteException {
//            PackageManager pm = mContext.getPackageManager();
//            List<ResolveInfo> list = pm.queryIntentServices(new Intent(arg0), 0);
//            if (list.size() == 0)
//                return ErrorCode.EC_LITESERVICE_REG_INVALID_SERVICE;
//            boolean flag = true;
//            for (ResolveInfo info : list) {
//                if (info.serviceInfo != null && info.serviceInfo.enabled) {
//                    flag = false;
//                    break;
//                }
//            }
//            if (flag)
//                return ErrorCode.EC_LITESERVICE_REG_INVALID_SERVICE;

            if (regConnectersMap.containsKey(arg0))
                return ErrorCode.EC_LITESERVICE_REG_SAME_SERVICE;
            XServiceConnection<?> c = new XServiceConnection<Object>(arg0) {
                @Override
                protected Object _getService() {
                    return null;
                }

                @Override
                public void onServiceDisconnected(ComponentName name) {
                    connectersMap.remove(getAction());
                    super.onServiceDisconnected(name);
                }
            };
            regConnectersMap.add(arg0, c);
            c.bindService(mContext, pkgName);
            return ErrorCode.EC_SUCCESS;
        }

        @Override
        public int unregisterService(String arg0) throws RemoteException {
            XServiceConnection<?> c = regConnectersMap.get(arg0);
            if (c == null)
                return ErrorCode.EC_LITESERVICE_NOT_REG_SERVICE;
            c.unbindService(mContext);
            regConnectersMap.remove(arg0);
            return ErrorCode.EC_SUCCESS;
        }

        @Override
        public IBinder getService(String action) throws RemoteException {
            XServiceConnection<?> c = connectersMap.get(action);
            if (c != null)
                return c.getIBinder();
            c = regConnectersMap.get(action);
            if (c != null)
                return c.getIBinder();
            throw new RemoteException("No such service handled action:" + action
                    + " has been bind!!");
        }

        @Override
        public ILiteCCConnectorService getCCConnectorService() throws RemoteException {
            while (cccServiceStub == null)
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            return cccServiceStub;
//            return LiteCCConnectorConnecter.connecter.getService();
        }

        @Override
        public ILiteCacheService getCacheService() throws RemoteException {
            while (cacheServiceStub == null)
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            return cacheServiceStub;
//            return LiteCacheConnecter.connecter.getService();
        }

        @Override
        public ILiteDBService getDBService() throws RemoteException {
            while (dbServiceStub == null)
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            return dbServiceStub;
//            return LiteDBConnecter.connecter.getService();
        }

        @Override
        public ILiteUserService getUserService() throws RemoteException {
            while (userServiceStub == null)
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            return userServiceStub;
//            return LiteUserConnecter.connecter.getService();
        }

        @Override
        public ILitePMService getPMService() throws RemoteException {
            while (pmServiceStub == null)
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            return pmServiceStub;
//            return LitePMConnecter.connecter.getService();
        }

        @Override
        public int getVersion() throws RemoteException {
            return LiteServiceConnecter.getVersion();
        }

        @Override
        public ILitePlayerClientService getPlayerClientService() throws RemoteException {
            while (playerClientServiceStub == null)
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            return playerClientServiceStub;
//            return LitePlayerClientServiceConnecter.connecter.getService();
        }

        @Override
        public ILitePlayerKernelProxyService getPlayerKernelProxyService() throws RemoteException {
            while (playerKernelServiceStub == null)
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            return playerKernelServiceStub;
//            return LitePlayerKernelServiceConnecter.connecter.getService();
        }

        @Override
        public ILiteConfigService getConfigService() throws RemoteException {
            while (configServiceStub == null)
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            return configServiceStub;
//            return LiteConfigConnecter.connecter.getService();
        }

        @Override
        public IDownloaderService getDownloaderService() throws RemoteException {
            while (downloaderServiceStub == null)
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            return downloaderServiceStub;
//            return LiteDownloadConnecter.connecter.getService();
        }
    }

    private MyStub stub = null;

    @Override
    public void onCreate() {
        super.onCreate();
        stub = new MyStub(this);
        Intent intent = new Intent(LiteServiceManager.LITE_SERVICE_ON_CREATE_BROADCAST_ACTION);
        intent.putExtra("package", getPackageName());
        intent.putExtra("version", LiteServiceConnecter.getVersion());
        sendBroadcast(intent);
    }

    @Override
    public void onDestroy() {
        Intent intent = new Intent(LiteServiceManager.LITE_SERVICE_ON_DESTROY_BROADCAST_ACTION);
        intent.putExtra("package", getPackageName());
        intent.putExtra("version", LiteServiceConnecter.getVersion());
        sendBroadcast(intent);
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return stub;
    }
}
